package com.wrt.wm.service.impl;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.UUID;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.wrt.wm.entity.AjaxResult;
import com.wrt.wm.entity.FontParameters;
import com.wrt.wm.entity.ResultImageInfo;
import com.wrt.wm.service.WaterMarkService;
import com.wrt.wm.util.DeleteFileUtil;
import com.wrt.wm.util.JudgeImageUtil;
import com.wrt.wm.util.RewriteImageUtil;
import com.wrt.wm.util.WaterMarkUtil;

import lombok.extern.log4j.Log4j2;
import net.coobird.thumbnailator.geometry.Positions;

@Service
@Log4j2
public class WaterMarkServiceImpl implements WaterMarkService {

    @Value("${temppath.source:temp_source}")
    private String sourcepath;

    @Autowired
    private JudgeImageUtil ji;
    @Autowired
    private RewriteImageUtil ri;
    @Autowired
    private WaterMarkUtil wmu;
    @Autowired
    private DeleteFileUtil deleteFile;

    @Override
    public AjaxResult addWordMark(MultipartFile file, String waterMarkContent, FontParameters fontParameters) {
        // 带有后缀（格式）的文件名
        String filename = file.getOriginalFilename();
        // 文件后缀（格式）
        String ext = FilenameUtils.getExtension(filename).toLowerCase();
        // 无后缀的文件名
        String filebasename = handleFileName(FilenameUtils.getBaseName(filename));
        File temp = multipartFileToFile(file, ext);
        AjaxResult judgeresult = ji.isImage(temp);
        if (judgeresult.getCode() == 0) {
            String srcImg = ri.handle(judgeresult.getMsg(), temp, (BufferedImage) judgeresult.getData());
            File srcImgFile = new File(srcImg);
            if (!srcImgFile.exists()) {
                return AjaxResult.fail("图片重绘失败");
            }
            wmu.setFontParam(fontParameters);
            String outImg = wmu.mark(srcImg, waterMarkContent);
            File outImgFile = new File(outImg);
            if (!outImgFile.exists()) {
                return AjaxResult.fail("水印添加失败");
            }
            deleteFile.cleanUp(temp, srcImgFile);
            String imgname = String.valueOf(filebasename) + "_wm." + ext;
            ResultImageInfo rii = new ResultImageInfo(file2base64(outImgFile), ext, imgname);
            return AjaxResult.success("处理完成", rii);
        } else {
            deleteFile.cleanUp(temp);
            return judgeresult;
        }
    }

    /**
     * 批量添加文字水印
     *
     * @param file             图片文件
     * @param waterMarkContent 水印内容
     * @param fontParameters
     * @return 水印添加结果
     */
    @Override
    public AjaxResult addWordBatchMark(MultipartFile file, String waterMarkContent, FontParameters fontParameters) {
        //水印
        String[] workMarks = new String[]{waterMarkContent};
        //拆分这批有多少个水印
        if (StringUtils.isNotBlank(waterMarkContent)) {
            workMarks = waterMarkContent.split(",");
        }
        List<Object> imgList = new ArrayList<>();
        //多个水印
        for (String workMark : workMarks) {
            AjaxResult ajaxResult = addWordMark(file, workMark, fontParameters);
            Object data = ajaxResult.getData();
            if (data instanceof ResultImageInfo) {
                ResultImageInfo imageInfo = (ResultImageInfo) data;
                imageInfo.setImgname(workMark + "." + imageInfo.getSuffix());
                imgList.add(imageInfo);
            }
        }
        return AjaxResult.success("处理完成", imgList);
    }

    @Override
    public AjaxResult addImgMark(MultipartFile srcfile, MultipartFile wmfile, String pname, Float alpha) {
        String filename = srcfile.getOriginalFilename();
        String ext = FilenameUtils.getExtension(filename).toLowerCase();
        String filebasename = handleFileName(FilenameUtils.getBaseName(filename));
        File srctemp = multipartFileToFile(srcfile, ext);
        File wmtemp = multipartFileToFile(wmfile,
                FilenameUtils.getExtension(wmfile.getOriginalFilename()).toLowerCase());
        AjaxResult handleresult = rewrite2Img(srctemp, wmtemp);
        if (handleresult.getCode() == 0) {
            Positions position = getPosition(pname);
            String[] imgs = (String[]) handleresult.getData();
            String outImg = wmu.mark(imgs[0], imgs[1], position, alpha);
            File outImgFile = new File(outImg);
            if (!outImgFile.exists()) {
                return AjaxResult.fail("水印添加失败");
            }
            deleteFile.cleanUp(srctemp, new File(imgs[0]), wmtemp, new File(imgs[1]));
            String imgname = String.valueOf(filebasename) + "_wm." + ext;
            ResultImageInfo rii = new ResultImageInfo(file2base64(outImgFile), ext, imgname);
            return AjaxResult.success("处理完成", rii);
        } else {
            return handleresult;
        }
    }

    /**
     * 处理文件名称，移除特殊符号
     *
     * @param filename 图片文件名
     * @return 处理后的文件名
     */
    private String handleFileName(String filename) {
        StringBuilder sbu = new StringBuilder();
        char[] chars = filename.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            int temp = chars[i];
            if (judgeNormal(temp)) {
                sbu.append(Character.valueOf(chars[i]));
            }
        }
        return sbu.toString();
    }

    /**
     * 判断字符是否属于常规字符
     *
     * @param parseChar 待判断的字符
     * @return true-属于常规字符;false-特殊字符
     */
    private boolean judgeNormal(int parseChar) {
        boolean result = false;
        int[] min = {33, 39, 44, 48, 62, 65, 91, 93, 95, 97, 8212, 8216, 8220, 8230, 12304, 12289, 12298, 19968, 65281,
                65288, 65292, 65306, 65311};
        int[] max = {34, 41, 46, 60, 63, 90, 91, 93, 95, 122, 8212, 8217, 8221, 8230, 12305, 12289, 12299, 40895,
                65281, 65289, 65292, 65307, 65311};
        for (int i = 0; i < min.length; i++) {
            if (min[i] <= parseChar && parseChar <= max[i]) {
                result = true;
                break;
            }
        }
        return result;
    }

    /**
     * MultipartFile对象转换为File对象
     *
     * @param mfile  MultipartFile对象
     * @param suffix 文件后缀名
     * @return File对象
     */
    private File multipartFileToFile(MultipartFile mfile, String suffix) {
        File sourceDir = new File(sourcepath);
        if (!sourceDir.exists()) {
            sourceDir.mkdir();
        }
        File file = new File(sourcepath + File.separator + UUID.randomUUID().toString() + "." + suffix);
        try (InputStream ins = mfile.getInputStream(); OutputStream os = new FileOutputStream(file);) {
            int bytesRead = 0;
            int limitbyte = 8192;
            byte[] buffer = new byte[limitbyte];
            while ((bytesRead = ins.read(buffer, 0, limitbyte)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
        } catch (Exception e) {
            log.info("输入流转换文件对象出错", e);
        }
        return file;
    }

    /**
     * 图片文件转换为base64字符串
     *
     * @param file 图片文件对象
     * @return base64字符串
     */
    private String file2base64(File file) {
        try {
            byte[] b = Files.readAllBytes(file.toPath());
            this.deleteFile.cleanUp(file);
            return Base64.getEncoder().encodeToString(b);
        } catch (IOException e) {
            this.deleteFile.cleanUp(file);
            log.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 重绘两个图片（图片水印）
     *
     * @param srctemp 待处理的文件对象
     * @param wmtemp  水印图片文件对象
     * @return 封装后的结果
     */
    private AjaxResult rewrite2Img(File srctemp, File wmtemp) {
        AjaxResult judgesrc = ji.isImage(srctemp);
        if (judgesrc.getCode() == 0) {
            AjaxResult judgewm = ji.isImage(wmtemp);
            if (judgewm.getCode() == 0) {
                String srcImg = ri.handle(judgesrc.getMsg(), srctemp, (BufferedImage) judgesrc.getData());
                File srcImgFile = new File(srcImg);
                if (!srcImgFile.exists()) {
                    return AjaxResult.fail("原图片重绘失败");
                }
                String wmImg = ri.handle(judgewm.getMsg(), wmtemp, (BufferedImage) judgewm.getData());
                File wmImgFile = new File(wmImg);
                if (!wmImgFile.exists()) {
                    return AjaxResult.fail("水印图片重绘失败");
                }
                String[] imgs = {srcImg, wmImg};
                return AjaxResult.success(null, imgs);
            } else {
                deleteFile.cleanUp(wmtemp);
                return judgewm;
            }
        } else {
            deleteFile.cleanUp(srctemp);
            return judgesrc;
        }
    }

    /**
     * 获取水印位置（图片水印）
     *
     * @param pname 位置枚举名称
     * @return 位置枚举项（默认居中）
     */
    private Positions getPosition(String pname) {
        if (StringUtils.isBlank(pname)) {
            return Positions.CENTER;
        } else {
            return Positions.valueOf(pname);
        }
    }
}
